package tms.util.logging;

import org.apache.log4j.Appender;
import org.apache.log4j.Layout;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
import tms.util.context.ApplicationContext;
import tms.util.context.LoggingConfig;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.Properties;
import java.util.logging.Level;

public class Log4jLoggerFactory extends LoggerFactoryBase {
    @Override
    void initLoggingFramework() {
        Properties properties = new Properties();
        properties.setProperty("log4j.rootLogger", "DEBUG, A1");
        properties.setProperty("log4j.appender.A1", "org.apache.log4j.ConsoleAppender");
        properties.setProperty("log4j.appender.A1.layout", "org.apache.log4j.SimpleLayout");
        PropertyConfigurator.configure(properties);
    }

    @Override
    public Logger getLogger(AreaType area) {
        return new Log4jLoggerAdapter(area);
    }

    private class Log4jLoggerAdapter implements Logger {
        private org.apache.log4j.Logger logger;

        public Log4jLoggerAdapter(AreaType area) {
            logger = org.apache.log4j.Logger.getLogger(area.path());
            logger.addAppender(buildAppender(area));
        }

        @Override
        public void info(String message) {
            logger.info(message);
        }

        @Override
        public void warning(String message) {
            logger.warn(message);
        }

        @Override
        public void warning(String message, Throwable cause) {
            logger.warn(message, cause);
        }

        @Override
        public void info(String message, Object... params) {
            info(MessageFormat.format(message, params));
        }

        @Override
        public void warning(String message, Object... params) {
            warning(MessageFormat.format(message, params));
        }

        @Override
        public void warning(String message, Throwable cause, Object... params) {
            warning(MessageFormat.format(message, params), cause);
        }

        @Override
        public void error(String message, Throwable cause) {
            logger.error(message, cause);
        }

        @Override
        public void error(String message, Throwable cause, Object... params) {
            logger.error(MessageFormat.format(message, params), cause);
        }

        private Appender buildAppender(AreaType area) {
            Appender retVal = null;
            try {
                Layout layout = new Layout() {
                    @Override
                    public String format(LoggingEvent loggingEvent) {
                        StringBuffer retVal = new StringBuffer(MessageFormat.format(
                                LOG_RECORD_FORMAT,
                                loggingEvent.getTimeStamp(),
                                loggingEvent.getLevel().toString(),
                                loggingEvent.getThreadName(),
                                loggingEvent.getMessage()
                        ));

                        ThrowableInformation throwableInformation = loggingEvent.getThrowableInformation();
                        if (throwableInformation != null) {
                            Throwable thrown = throwableInformation.getThrowable();
                            if (thrown != null) {
                                StringWriter stringWriter = new StringWriter();
                                thrown.printStackTrace(new PrintWriter(stringWriter));
                                retVal.append(stringWriter.getBuffer());
                            }
                        }

                        return retVal.toString();
                    }

                    @Override
                    public boolean ignoresThrowable() {
                        return true;
                    }
                    @Override
                    public void activateOptions() {
                    }
                };
                LoggingConfig loggingConfig = ApplicationContext.getLoggingConfig();
                RollingFileAppender rollingFileAppender = new RollingFileAppender(layout, loggingConfig.getDirectory() + "/" + MessageFormat.format(loggingConfig.getFileNamePattern(), area.name().toLowerCase()));
                rollingFileAppender.setMaximumFileSize(loggingConfig.getFileMaxSize());
                rollingFileAppender.setMaxBackupIndex(loggingConfig.getFilesCount() - 1);
                retVal = rollingFileAppender;
            } catch (IOException e) {
                java.util.logging.Logger.getLogger("").log(Level.SEVERE, "Error building TMS application logger.", e);
            }
            return retVal;
        }
    }    
}
